package mission2.model;
import java.io.IOException;
import java.io.StringReader;


public class ATree {
	private BTNode<String> tree;
	
	public ATree(String s) throws IOException 
	//Initialisation d'un arbre analytique dont la racine vaut null
	{
		tree= new BTNode<String>("", null,null,null );
		fillATree(StringToList(s));
	}
	public BTNode<String> getBTNODE()
	{
		return tree;
	}
/*
 * @pre: String[] t
 * @post: Remplit correctement un arbre pour qu'il represente l'expression analytique t
 * 		  exemple: sin(x)
 *        element:sin
 *   left:   x      right:null
 *   
 */
	public void fillATree(String[] t)
	{
		int k=1;//itérateur du tableau t
		BTNode<String> iterateur=tree;
		while(t[k]!=null && k<t.length)
		{
			String Bloc=t[k]; // Evite de faire appel au tableau à chaque reprise
			k++;
			if(isLeftParentesis(Bloc))// Cas de la parenthèse gauche
			{// on descend vers la gauche de l'arbre
				if(!iterateur.hasLeft())
				{
					iterateur.setLeft(new BTNode<String>("",null,null,iterateur));
				}		
				iterateur=(BTNode<String>)iterateur.getLeft();
			}
			else 
				{
					if(Utils.isAnInteger(Bloc)||isAVariable(Bloc))
					{	//Cas du nombre: inscrire le nombre et remonter
						iterateur.setElement(Bloc);
						
						iterateur=(BTNode<String>) iterateur.getParent();
					}
					else
					{
						if(isAnOperand(Bloc))
						{//operateur: inscrire l'operateur et aller a droite
							iterateur.setElement(Bloc);
							if(!iterateur.hasRight())
							{
								iterateur.setRight(new BTNode<String>("",null,null,iterateur));
							}
							iterateur=(BTNode<String>) iterateur.getRight();
						}
						else
							if(isRightParentesis(Bloc))
							{//parenthese droite: on remonte si le noeud a un parent
								if(iterateur.hasParent())
								{
									iterateur=(BTNode<String>)iterateur.getParent();
								}
								
							}
							else//fonction: inscrire la fonction
							{
								iterateur.setElement(Bloc);
								
							}
					}
				
				}	
		}
	}
	/*
	 * @pre: s doit être une variable du type String representant une expression analytique valable.
	 *       Le programme s'exécute correctement même si une fonction inconnue est inscrite dans s.
	 *       si s contient: "nimporte(x)" le tableau renvoyé sera donné par
	 *       t[1]="nimporte"
	 *       t[2]="("
	 *       t[3]="x"
	 *       t[4]=")"
	 *       
	 * @post: renvoie un tableau dont chaque entree est un bloc
	 *        un bloc est soit une fonction soit un operande soit une parenthèse ou un nombre
	 */
	private String[] StringToList (String s) throws IOException
	{
		String[] t=new String[s.length()+2];
		StringReader reader=new StringReader(s);
		int end= reader.read();//pour arreter la lecture
		String temp=Character.toString((char)end);
		int k=1;//indice du tableau
		while(end!=-1)
		{
			if (Utils.isAnInteger(temp))//Si temp est un nombre
			{
				end=reader.read();
				String temp2=Character.toString((char)end);
				if (Utils.isAnInteger(temp2))//charactère suivant est un nombre
				{ 
					temp+=temp2;
					
				}
				else//charactère suivant n'est pas un nombre
				{
					t[k]=temp;
					temp=temp2;
					k++;
				}
			}
			else
			{
				if(isAnOperand(temp)||isRightParentesis(temp)||isLeftParentesis(temp)||isAVariable(temp))
				{// Si l'un de ces symboles: directement rajouter dans le tableau
					
					t[k]=temp;
					end=reader.read();
					temp=Character.toString((char)end);
					k++;
				}
				else
				{ //en cas d'une fonction ex: sin, cos,... ou tout autre séquence inconnue
					end=reader.read();
					
					String temp2=Character.toString((char)end);
					if (Utils.isAnInteger(temp2)||isAnOperand(temp2)||isRightParentesis(temp2)||isLeftParentesis(temp2)||isAVariable(temp2))
					{
						t[k]=temp;
						k++;
						temp=temp2;
					}
					else
					{
						temp+=temp2;
					}	
				}
			}
		}
		return t;	
	}
	private  boolean isLeftParentesis(String s)
	{//parenthèse: (
		return s.equals("(");
	}
	private boolean isRightParentesis(String s)
	{//parenthèse: )
		return s.equals(")");
	}
	private static boolean isAVariable(String s)
	{//variable
		return s.equals("x");
	}
	private static boolean isAnOperand(String s)
	{//renvoie true si s est un operande 
		return s.equals("^") ||s.equals("-")||s.equals("+")||s.equals("*")||s.equals("/");
	}
}


